//
//  ViewController.m
//  runloop让线程保活
//
//  Created by Hello Cai on 2021/7/22.
//

#import "ViewController.h"
#import "NSThread+Extension.h"
#import "HRThread.h"

@interface ViewController ()

@property (strong, nonatomic) HRThread *thread;
@property (assign, nonatomic, getter=isStoped) BOOL stopped;

@end

@implementation ViewController

//监听runloop的状态
void observeRunLoopActicities(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
    switch (activity) {
        case kCFRunLoopEntry:
            NSLog(@"kCFRunLoopEntry");
            break;
        case kCFRunLoopBeforeTimers:
            NSLog(@"kCFRunLoopBeforeTimers");
            break;
        case kCFRunLoopBeforeSources:
            NSLog(@"kCFRunLoopBeforeSources");
            break;
        case kCFRunLoopBeforeWaiting:
            NSLog(@"kCFRunLoopBeforeWaiting");
            break;
        case kCFRunLoopAfterWaiting:
            NSLog(@"kCFRunLoopAfterWaiting");
            break;
        case kCFRunLoopExit:
            NSLog(@"kCFRunLoopExit");
            break;
        default:
            break;
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    __weak typeof(self) weakSelf = self;
    
    self.stopped = NO;
    

    //用initWithTarget:selector:object:构造的block，iOS2系统以上
    self.thread = [[HRThread alloc] hr_initWithBlock:^{
        NSLog(@"%@----begin----", [NSThread currentThread]);
        // 创建Observer
        CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, observeRunLoopActicities, NULL);
        // 添加Observer到RunLoop中，监听RunLoop状态
        CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
        
        // 往RunLoop里面添加Source\Timer\Observer
        [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
        
        //这里判断条件必须这么写，否则当控制器销毁时，self为nil，会导致while的判断条件为真，再次开启runloop，子线程无法销毁
        while (weakSelf && !weakSelf.isStoped) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            NSLog(@"结束runloop");
        }
        NSLog(@"%@----end----", [NSThread currentThread]);
        CFRelease(observer);
    }];
    [self.thread start];
    
    
    //iOS10系统以上
#if 0
    if (@available(iOS 10.0, *)) {
        self.thread = [[HRThread alloc] initWithBlock:^{
            NSLog(@"%@----begin----", [NSThread currentThread]);
            
            // 创建Observer
            CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, observeRunLoopActicities, NULL);
            // 添加Observer到RunLoop中，监听RunLoop状态
            CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
            
            
            // 往RunLoop里面添加Source\Timer\Observer
            [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
            
            //这里判断条件必须这么写，否则当控制器销毁时，self为nil，会导致while的判断条件为真，再次开启runloop，子线程无法销毁
            while (weakSelf && !weakSelf.isStoped) {
                NSLog(@"开启runloop");
                /*用runMode:beforeDate:方式启动runloop，runloop没事情做时就会进入睡眠（kCFRunLoopBeforeWaiting），且卡在这一行代码不继续走了。
                  等到有事情做时，runloop会被唤醒，检查timer、source（kCFRunLoopBeforeTimers、kCFRunLoopBeforeSources）哪一个需要处理，然后就去干活。
                 事情干完后，runloop就会退出（kCFRunLoopExit），退出后代码才会继续往下走。
                 */
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
                NSLog(@"结束runloop");
            }
            
            NSLog(@"%@----end----", [NSThread currentThread]);
            
            // NSRunLoop的run方法是无法停止的，它专门用于开启一个永不销毁的线程（NSRunLoop）
            //        [[NSRunLoop currentRunLoop] run];
            /* run方法的解释：
             it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:.
             In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers
             翻译过来就是run方法内部做的事情是重复的调用runMode:beforeDate:
             */
            // 释放
            CFRelease(observer);
        }];
        [self.thread start];
    }
#endif
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (!self.thread) return;
    
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}

// 子线程需要执行的任务
- (void)test
{
    NSLog(@"执行任务：%s %@", __func__, [NSThread currentThread]);
}

- (IBAction)stop{
    if (!self.thread) return;
    // 在子线程调用stop
    // waitUntilDone:YES表示等performSelector执行完后，程序才会往下走.
    // 这里必须填YES
    [self performSelector:@selector(stopThread) onThread:self.thread withObject:nil waitUntilDone:YES];
}

// 用于停止子线程的RunLoop
- (void)stopThread
{
    // 设置标记为NO
    self.stopped = YES;
    
    // 停止RunLoop
    CFRunLoopStop(CFRunLoopGetCurrent());
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
    self.thread = nil;
}

- (void)dealloc
{
    NSLog(@"%s", __func__);
    
    [self stop];
    
    NSLog(@"控制器彻底销毁了");
}

@end
